/*
 * This is based off the O3D instance-override sample, modified for this
 * window demo.
 *
 * Copyright 2009, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// ********************** InstanceOverrideWindow *******************************

/***
 * A InstanceOverrideWindow is a window that shows a 3d model.
 * @constructor.
 */
function __InstanceOverrideWindow() {
}

/**
 * Makes __InstanceOverrideWindow inherit from Window.
 */
__InstanceOverrideWindow.prototype = new __Window();

/**
 * Initializes an __InstanceOverrideWindow window
 * @param {Object} spec Intialization arguments. See __Window.init.
 */
__InstanceOverrideWindow.prototype.init = function(spec) {
  __Window.prototype.init.call(this, spec);
  var ui = this.getUI();
  ui.addOnRenderWindow(this);

  var pack = g_client.createPack();
  this.appPack = pack;
  this.clock = 0;

  /* Load the effect for our sphere from our file.
     Effects, stored in a hidden textarea for simplicity, contain the
     functions that define the vertex and pixel shaders used by our shape.

     Here, we calculate phong illumination in our vertex shader and pass the
     resultant color to our pixel shader, which does nothing except output its
     given (input) color.
  */
  var defaultEffect = pack.createObject('Effect');
  defaultEffect.loadFromFXString(
      document.getElementById('instanceoverrideshader').value);

  // Create a Material for the effect.
  var material = pack.createObject('Material');

  // Apply our effect to this material. The effect tells the 3D hardware
  // which shader to use.
  material.effect = defaultEffect;

  // Set the material's drawList
  material.drawList = this.viewInfo.performanceDrawList;

  // This will create our quadColor parameter on the material.
  defaultEffect.createUniformParameters(material);

  // Light position
  var light_pos_param = material.getParam('light_pos');
  light_pos_param.value = [1000, 1000, 0];

  // Phong components of the light source
  var light_ambient_param = material.getParam('light_ambient');
  var light_diffuse_param = material.getParam('light_diffuse');
  var light_specular_param = material.getParam('light_specular');

  // White ambient light
  light_ambient_param.value = [0.1, 0.1, 0.1, 1];
  // Reddish diffuse light
  light_diffuse_param.value = [1, 1, 1, 1];
  // White specular light
  light_specular_param.value = [0.5, 0.5, 0.5, 1];

  // Shininess of the material (for specular lighting)
  var shininess_param = material.getParam('shininess');
  shininess_param.value = 5.0;

  // Position of the camera.
  // (should be the same as the 'eye' position given below)
  var camera_pos_param = material.getParam('camera_pos');
  // Camera is at (0, 0, 3).
  camera_pos_param.value = [0, 0, 3];

  // Create a sphere.
  var shape = o3djs.primitives.createSphere(pack, material, 40, 10, 12);
  shape.createDrawElements(pack, null);

  this.createInstances(pack, shape);
  this.setProjection();
};

/**
 * Closes a __InstanceOverrideWindow.
 */
__InstanceOverrideWindow.prototype.close = function() {
  var ui = this.getUI();
  ui.removeOnRenderWindow(this);
  this.appRoot.parent = null;
  this.applPack.destroy();
  __Window.prototype.resizeWindow.close(this, size);
};

/**
 * Handler for onRender.
 * @param {number} elapsedTime time in seconds since the last call to onRender.
 */
__InstanceOverrideWindow.prototype.onRender = function(elapsedTime) {
  // Get the number of seconds since the last render.
  this.clock += elapsedTime;

  var x = Math.sin(this.clock * 0.3) * 1000;
  var z = Math.cos(this.clock * 0.3) * 1000;
  var y = Math.sin(this.clock * 0.7) * 500;

  this.viewInfo.drawContext.view = g_math.matrix4.lookAt(
      [x, y, z],
      [0, 0, 0],
      [0, 1, 0]);
};

/**
 * Sets the projection matrix.
 */
__InstanceOverrideWindow.prototype.setProjection = function() {
  // Create our projection matrix, with a vertical field of view of 45 degrees
  // a near clipping plane of 0.1 and far clipping plane of 100.
  var fovInRad = 45 * Math.PI / 180
  var nearPlane = 0.1;
  var farPlane = 10000;
  var aspectRatio = this.rect.width / this.rect.height;
  this.setPerspective(
      fovInRad,
      aspectRatio,
      nearPlane,
      farPlane);
};

/**
 * Resizes this window.
 * @param {Point} size where x = width, y = height.
 */
__InstanceOverrideWindow.prototype.resizeWindow = function(size) {
  __Window.prototype.resizeWindow.call(this, size);
  this.setProjection();
};

/**
 * Creates a grid of instances of the shape passed in
 * @param {client3d.Pack} pack Pack to add transforms to.
 * @param {client3d.Shape} shape Shape to instance.
 */
__InstanceOverrideWindow.prototype.createInstances = function(pack, shape) {
  // now make a grid of transforms and put a teapot instance on each one
  for (var x = 0; x < 5; x++) {
    for (var y = 0; y < 5; y++) {
      for (var z = 0; z < 5; z++) {
        var transform = this.appPack.createObject('Transform');
        transform.parent = this.root;
        transform.addShape(shape);
        transform.translate((x - 2) * 100,
                            (y - 2) * 100,
                            (z - 2) * 100);
        transform.createParam('colorMult', 'ParamFloat4').value = [
            x * 0.2,
            y * 0.2,
            z * 0.2,
            1];
      }
    }
  }
};

